package com.cby.operation.common.widget.richtext

import android.graphics.Color
import android.text.Editable
import android.text.Html.TagHandler
import android.text.Spannable
import android.text.Spanned
import android.text.TextUtils
import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan
import android.text.style.URLSpan
import android.util.Log
import android.view.View
import org.xml.sax.XMLReader
import java.util.*

/**
 * 描述信息
 *
 * @author 徐智伟
 * @create 2020-03-27
 */
class HtmlTagHandler(private val listener: OnTextClickListener?) : TagHandler {
    /**
     * 存放各个标签的开始和结束标签下标
     */
    private val indexStack: Stack<Int> = Stack()

    override fun handleTag(opening: Boolean, tag: String, output: Editable,
                           xmlReader: XMLReader) {
        if (opening) {
            //process start tag,like <span>
            handleStartTag(tag, output, xmlReader)
            indexStack.push(output.length)
        } else {
            //process end tag, like "</span>"
            val startIndex: Int
            startIndex = if (indexStack.isEmpty()) {
                0
            } else {
                indexStack.pop()
            }

            //结束标签逻辑处理
            handleEndTag(startIndex, output.length, tag,
                    output, xmlReader)
        }
    }

    private fun handleStartTag(tag: String, output: Editable,
                               xmlReader: XMLReader) {
        when (tag.toLowerCase()) {
            HTML_TAG_SPAN -> spanStartTag(tag, output, xmlReader)
            HTML_TAG_A -> aStartTag(tag, output, xmlReader)
            else -> {
            }
        }
    }

    private fun handleEndTag(startIndex: Int, endIndex: Int, tag: String, output: Editable,
                             xmlReader: XMLReader) {
        when (tag.toLowerCase()) {
            HTML_TAG_SPAN -> spanEndTag(startIndex, endIndex, tag, output, xmlReader)
            HTML_TAG_A -> aEndTag(startIndex, endIndex, tag, output, xmlReader)
            else -> {
            }
        }
    }

    /**
     * 开始span标签处理
     * @param tag
     * @param output
     * @param xmlReader
     */
    private fun spanStartTag(tag: String, output: Editable,
                             xmlReader: XMLReader) {
        val styleCss = HtmlTagHelper.getAttribute(xmlReader, "style")
        if (styleCss != null) {
            parseCssStyle(styleCss, output)
        }
    }

    /**
     * span结束标签处理
     * @param startIndex
     * @param endIndex
     * @param tag
     * @param output
     * @param xmlReader
     */
    private fun spanEndTag(startIndex: Int, endIndex: Int, tag: String, output: Editable,
                           xmlReader: XMLReader) {
        val cssStyle = HtmlTagHelper.getLast(output, CssStyle::class.java) ?: return
        if (cssStyle.color != 0) {
            val where = output.getSpanStart(cssStyle)
            output.removeSpan(cssStyle)

            //移除原有标记，因为原有标记不是默认的24种ParcelableSpan子类，因此无法渲染文本
            output.setSpan(ForegroundColorSpan(cssStyle.color),
                    where, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
        }
    }

    /**
     * 开始span标签处理
     * @param tag
     * @param output
     * @param xmlReader
     */
    private fun aStartTag(tag: String, output: Editable,
                          xmlReader: XMLReader) {
        val href = HtmlTagHelper.getAttribute(xmlReader, "href")
        val length = output.length
        output.setSpan(
            href?.let { LinkHolder(it) }, length, length,
                Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
    }

    /**
     * span结束标签处理
     * @param startIndex
     * @param endIndex
     * @param tag
     * @param output
     * @param xmlReader
     */
    private fun aEndTag(startIndex: Int, endIndex: Int, tag: String, output: Editable,
                        xmlReader: XMLReader) {
        val linkHolder = HtmlTagHelper.getLast(output, LinkHolder::class.java)
        if (linkHolder != null) {
            val start = output.getSpanStart(linkHolder)
            // int end = output.getSpanEnd(linkHolder);
            output.removeSpan(linkHolder)
            output.setSpan(object : ClickableSpan() {
                override fun onClick(widget: View) {
                    listener?.onTextClick(linkHolder.url)
                    Log.i(TAG, "click custom url =" + linkHolder.url)
                }
            }, start, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
        }


        /*URLSpan[] urlSpans = output.getSpans(0, output.length(), URLSpan.class);

    int size = urlSpans == null ? 0 : urlSpans.length;
    for (int i = 0; i < size; i ++) {
      resetLinkSpan(output, urlSpans[i]);
    }*/
    }

    private fun resetLinkSpan(spanned: Spannable, urlSpan: URLSpan) {
        val start = spanned.getSpanStart(urlSpan)
        val end = spanned.getSpanEnd(urlSpan)
        spanned.removeSpan(urlSpan)
        val linkHolder = LinkHolder(urlSpan.url)
        spanned.setSpan(object : ClickableSpan() {
            override fun onClick(widget: View) {
                listener?.onTextClick(linkHolder.url)
            }
        }, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
    }

    /**
     * css样式解析
     * @param style
     * @param output
     */
    private fun parseCssStyle(style: String, output: Editable) {
        if (TextUtils.isEmpty(style)) {
            return
        }
        val length = output.length
        val cssArray = style.split(";".toRegex()).toTypedArray()

        //颜色值
        var color = 0
        for (css in cssArray) {
            if (TextUtils.isEmpty(css)) {
                break
            }
            val splitCss = css.trim { it <= ' ' }.split(":".toRegex()).toTypedArray()
            val cssName = splitCss[0]

            //判断是否是color
            if (CSS_NAME_COLOR == cssName.trim { it <= ' ' }) {
                val colorString = splitCss[1].trim { it <= ' ' }.replace(" ".toRegex(), "")
                        .toLowerCase()
                color = parseColor(colorString)
                output.setSpan(CssStyle(0, color), length, length,
                        Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
            }
        }
    }

    /**
     * 解析颜色值
     * @param colorString
     * @return
     */
    private fun parseColor(colorString: String): Int {
        var colorString = colorString
        var color = 0
        if (colorString.startsWith("rgb") || colorString.startsWith("rgba")) {
            val start = colorString.indexOf("(")
            val end = colorString.indexOf(")")
            colorString = colorString.substring(start, end)
            colorString = colorString.replace(" ".toRegex(), "").replace("\\(".toRegex(), "")
            val colorArray = colorString.split(",".toRegex()).toTypedArray()
            color = if (colorArray.size == 3) {
                Color.argb(255, colorArray[0].toInt(), colorArray[1].toInt(), colorArray[2].toInt())
            } else {
                Color.argb(colorArray[3].toInt(), colorArray[0].toInt(), colorArray[1].toInt(), colorArray[2].toInt())
            }
        } else if (colorString.length == 7) {
            //后台传的color可能出现非标准的值，这里
            color = Color.parseColor(colorString)
        }
        return color
    }

    private class LinkHolder @JvmOverloads constructor(var url: String, var color: Int = LINK_COLOR,
                                                       /**
                                                        * 下划线标识
                                                        */
                                                       var underLine: Boolean = false) {
        companion object {
            /**
             * 默认颜色值
             */
            private val LINK_COLOR = Color.parseColor("#00ff00")
        }
    }

    /*
   *自定义
   */
    private class CssStyle(var textSize: Int, var color: Int)
    private class ATagSpan(var href: String)
    interface OnTextClickListener {
        fun onTextClick(textUrl: String?)
    }

    companion object {
        private const val TAG = "HtmlTagHandler"

        /**
         * html标签
         */
        private const val HTML_TAG_SPAN = "span"
        private const val HTML_TAG_A = "ajump"
        private const val CSS_NAME_COLOR = "color"
        private const val CSS_NAME_FONT_SIZE = "font-size"
    }
}